package storage

import (
	"fmt"
	"io"
	"log"
)

// HybridStorage 混合存储：本地缓存 + MinIO持久化
type HybridStorage struct {
	local      *LocalStorage
	minio      *MinIOStorage
	uploadChan chan uploadTask
}

// uploadTask 异步上传任务
type uploadTask struct {
	data        []byte
	filename    string
	contentType string
}

// NewHybridStorage 创建混合存储实例
func NewHybridStorage(config Config) (*HybridStorage, error) {
	// 创建本地存储（作为缓存）
	local := NewLocalStorage(config)

	// 创建MinIO存储（作为持久化）
	minio, err := NewMinIOStorage(config)
	if err != nil {
		return nil, fmt.Errorf("初始化MinIO失败: %v", err)
	}

	// 创建异步上传通道
	uploadChan := make(chan uploadTask, 100)

	hybrid := &HybridStorage{
		local:      local,
		minio:      minio,
		uploadChan: uploadChan,
	}

	// 启动异步上传协程
	go hybrid.asyncUploadWorker()

	log.Println("混合存储模式已启动：本地缓存 + MinIO异步上传")
	return hybrid, nil
}

// asyncUploadWorker 异步上传工作协程
func (s *HybridStorage) asyncUploadWorker() {
	for task := range s.uploadChan {
		// 异步上传到MinIO
		if err := s.uploadToMinIO(task); err != nil {
			log.Printf("异步上传到MinIO失败 %s: %v", task.filename, err)
			// 可以在这里实现重试逻辑
		} else {
			log.Printf("异步上传到MinIO成功: %s", task.filename)
		}
	}
}

// uploadToMinIO 上传数据到MinIO
func (s *HybridStorage) uploadToMinIO(task uploadTask) error {
	reader := io.NopCloser(io.Reader(newBytesReader(task.data)))
	_, err := s.minio.SaveFile(reader, task.filename, task.contentType)
	return err
}

// SaveFile 保存文件（同步保存到本地，异步上传到MinIO）
func (s *HybridStorage) SaveFile(data io.Reader, filename string, contentType string) (string, error) {
	// 读取数据到内存
	fileData, err := io.ReadAll(data)
	if err != nil {
		return "", fmt.Errorf("读取文件数据失败: %v", err)
	}

	// 1. 同步保存到本地（快速）
	localReader := newBytesReader(fileData)
	_, err = s.local.SaveFile(localReader, filename, contentType)
	if err != nil {
		return "", fmt.Errorf("保存到本地失败: %v", err)
	}

	// 2. 异步上传到MinIO（不阻塞）
	select {
	case s.uploadChan <- uploadTask{
		data:        fileData,
		filename:    filename,
		contentType: contentType,
	}:
		// 任务已加入队列
	default:
		log.Printf("警告: 上传队列已满，跳过MinIO上传: %s", filename)
	}

	// 返回本地URL（通过服务转发）
	return s.minio.GetFileURL(filename), nil
}

// GetFile 获取文件（优先从本地缓存，不存在则从MinIO获取并缓存）
func (s *HybridStorage) GetFile(filename string) (io.ReadCloser, error) {
	// 1. 先尝试从本地获取
	exists, err := s.local.FileExists(filename)
	if err == nil && exists {
		log.Printf("从本地缓存获取文件: %s", filename)
		return s.local.GetFile(filename)
	}

	// 2. 本地不存在，从MinIO获取
	log.Printf("本地缓存未命中，从MinIO获取: %s", filename)
	minioReader, err := s.minio.GetFile(filename)
	if err != nil {
		return nil, fmt.Errorf("从MinIO获取文件失败: %v", err)
	}

	// 3. 读取MinIO数据并缓存到本地
	fileData, err := io.ReadAll(minioReader)
	minioReader.Close()
	if err != nil {
		return nil, fmt.Errorf("读取MinIO文件失败: %v", err)
	}

	// 4. 异步保存到本地缓存
	go func() {
		localReader := newBytesReader(fileData)
		if _, err := s.local.SaveFile(localReader, filename, ""); err != nil {
			log.Printf("缓存文件到本地失败 %s: %v", filename, err)
		} else {
			log.Printf("文件已缓存到本地: %s", filename)
		}
	}()

	// 5. 返回数据给客户端
	return io.NopCloser(newBytesReader(fileData)), nil
}

// DeleteFile 删除文件（同时删除本地和MinIO）
func (s *HybridStorage) DeleteFile(filename string) error {
	// 删除本地文件
	if err := s.local.DeleteFile(filename); err != nil {
		log.Printf("删除本地文件失败 %s: %v", filename, err)
	}

	// 删除MinIO文件
	if err := s.minio.DeleteFile(filename); err != nil {
		return fmt.Errorf("删除MinIO文件失败: %v", err)
	}

	return nil
}

// GetFileURL 获取文件访问URL（通过服务转发）
func (s *HybridStorage) GetFileURL(filename string) string {
	return s.minio.GetFileURL(filename)
}

// FileExists 检查文件是否存在（优先检查本地，再检查MinIO）
func (s *HybridStorage) FileExists(filename string) (bool, error) {
	// 先检查本地
	exists, err := s.local.FileExists(filename)
	if err == nil && exists {
		return true, nil
	}

	// 再检查MinIO
	return s.minio.FileExists(filename)
}

// Close 关闭混合存储（关闭上传通道）
func (s *HybridStorage) Close() {
	close(s.uploadChan)
}

// newBytesReader 创建字节读取器
func newBytesReader(data []byte) io.Reader {
	return &bytesReader{data: data, pos: 0}
}

// bytesReader 可重复读取的字节读取器
type bytesReader struct {
	data []byte
	pos  int
}

func (r *bytesReader) Read(p []byte) (n int, err error) {
	if r.pos >= len(r.data) {
		return 0, io.EOF
	}
	n = copy(p, r.data[r.pos:])
	r.pos += n
	return n, nil
}
